/**
 * @file error_codes.c
 * @brief 104协议错误码实现
 * @details 本文件实现了104协议的错误码管理功能，包括错误码描述、错误分类、
 *          错误处理等核心功能。支持通用错误、APDU错误、ASDU错误、数据类型错误、
 *          文件传输错误、参数错误、系统错误、通信错误等多种错误类型。
 * 
 * @author zyb
 * @date 2025-10-02
 * @version 1.0
 * 
 * @note 错误码定义遵循104协议规范，每个错误码都有对应的描述信息和错误级别
 * @warning 错误码一旦定义不应随意修改，以保持向后兼容性
 * 
 * @see error_codes.h
 * @see protocol_types.h
 */

#include "error_codes.h"
#include "../../../../../common/logs/include/logger.h"
#include <string.h>

// 定义模块名称
#define LOG_MODULE_NAME "ERROR_CODES"

/* ==================== 错误码描述表 ==================== */

/**
 * @brief 错误码描述结构
 * @details 用于存储错误码的详细信息，包括错误码值、描述文本、是否为致命错误、
 *          是否可恢复等属性。这个结构体用于构建错误码查找表。
 */
typedef struct {
    protocol_error_t code;        /**< 错误码值 */
    const char* description;      /**< 错误描述文本 */
    int is_fatal;                 /**< 是否为致命错误 (1:致命, 0:非致命) */
    int is_recoverable;           /**< 是否可恢复 (1:可恢复, 0:不可恢复) */
} error_description_t;

/**
 * @brief 错误码描述表
 * @details 包含所有104协议错误码的详细描述信息，按照错误码值排序。
 *          每个错误码都有对应的中文描述、致命性标志和可恢复性标志。
 *          这个表用于错误码查找和错误信息获取。
 */
static const error_description_t error_descriptions[] = {
    /* 成功 */
    {PROTOCOL_SUCCESS, "成功", 0, 0},
    
    /* 通用错误码 */
    {PROTOCOL_ERROR_INVALID_PARAM, "无效参数", 0, 1},
    {PROTOCOL_ERROR_NULL_POINTER, "空指针", 1, 0},
    {PROTOCOL_ERROR_BUFFER_TOO_SMALL, "缓冲区太小", 0, 1},
    {PROTOCOL_ERROR_BUFFER_OVERFLOW, "缓冲区溢出", 1, 0},
    {PROTOCOL_ERROR_INVALID_LENGTH, "无效长度", 0, 1},
    {PROTOCOL_ERROR_CHECKSUM_MISMATCH, "校验和不匹配", 0, 1},
    {PROTOCOL_ERROR_TIMEOUT, "超时", 0, 1},
    {PROTOCOL_ERROR_MEMORY_ALLOCATION, "内存分配失败", 1, 0},
    {PROTOCOL_ERROR_INVALID_FORMAT, "无效格式", 0, 1},
    {PROTOCOL_ERROR_NOT_IMPLEMENTED, "未实现", 0, 0},
    
    /* APDU错误码 */
    {PROTOCOL_ERROR_APDU_INVALID_START, "无效启动字符", 0, 1},
    {PROTOCOL_ERROR_APDU_INVALID_LENGTH, "无效长度", 0, 1},
    {PROTOCOL_ERROR_APDU_INVALID_CONTROL, "无效控制域", 0, 1},
    {PROTOCOL_ERROR_APDU_SEQUENCE_ERROR, "序列号错误", 0, 1},
    {PROTOCOL_ERROR_APDU_FORMAT_ERROR, "格式错误", 0, 1},
    
    /* ASDU错误码 */
    {PROTOCOL_ERROR_ASDU_INVALID_TYPE, "无效类型标识", 0, 1},
    {PROTOCOL_ERROR_ASDU_INVALID_VSQ, "无效可变结构限定词", 0, 1},
    {PROTOCOL_ERROR_ASDU_INVALID_COT, "无效传送原因", 0, 1},
    {PROTOCOL_ERROR_ASDU_INVALID_ADDRESS, "无效地址", 0, 1},
    {PROTOCOL_ERROR_ASDU_DATA_MISMATCH, "数据不匹配", 0, 1},
    
    /* 数据类型错误码 */
    {PROTOCOL_ERROR_DATA_INVALID_VALUE, "无效数据值", 0, 1},
    {PROTOCOL_ERROR_DATA_OUT_OF_RANGE, "数据超出范围", 0, 1},
    {PROTOCOL_ERROR_DATA_INVALID_QUALITY, "无效品质描述词", 0, 1},
    {PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP, "无效时间戳", 0, 1},
    {PROTOCOL_ERROR_DATA_CONVERSION_FAILED, "数据转换失败", 0, 1},
    
    /* 文件传输错误码 */
    {PROTOCOL_ERROR_FILE_NOT_FOUND, "文件未找到", 0, 1},
    {PROTOCOL_ERROR_FILE_ACCESS_DENIED, "文件访问被拒绝", 0, 1},
    {PROTOCOL_ERROR_FILE_TRANSFER_FAILED, "文件传输失败", 0, 1},
    {PROTOCOL_ERROR_FILE_CHECKSUM_ERROR, "文件校验和错误", 0, 1},
    {PROTOCOL_ERROR_FILE_SIZE_MISMATCH, "文件大小不匹配", 0, 1},
    
    /* 参数错误码 */
    {PROTOCOL_ERROR_PARAM_INVALID_ID, "无效参数ID", 0, 1},
    {PROTOCOL_ERROR_PARAM_READ_FAILED, "参数读取失败", 0, 1},
    {PROTOCOL_ERROR_PARAM_WRITE_FAILED, "参数写入失败", 0, 1},
    {PROTOCOL_ERROR_PARAM_VALIDATION_FAILED, "参数验证失败", 0, 1},
    
    /* 系统错误码 */
    {PROTOCOL_ERROR_SYSTEM_INIT_FAILED, "系统初始化失败", 1, 0},
    {PROTOCOL_ERROR_SYSTEM_NOT_READY, "系统未就绪", 0, 1},
    {PROTOCOL_ERROR_SYSTEM_BUSY, "系统忙", 0, 1},
    {PROTOCOL_ERROR_SYSTEM_SHUTDOWN, "系统关闭", 1, 0},
    
    /* 通信错误码 */
    {PROTOCOL_ERROR_COMM_LINK_DOWN, "通信链路断开", 0, 1},
    {PROTOCOL_ERROR_COMM_TIMEOUT, "通信超时", 0, 1},
    {PROTOCOL_ERROR_COMM_FRAME_ERROR, "通信帧错误", 0, 1},
    {PROTOCOL_ERROR_COMM_PROTOCOL_ERROR, "通信协议错误", 0, 1},
    
    /* 未知错误 */
    {PROTOCOL_ERROR_UNKNOWN, "未知错误", 1, 0}
};

/* ==================== 错误处理函数实现 ==================== */

/**
 * @brief 获取错误码对应的错误描述
 * @details 根据错误码值查找对应的错误描述文本。函数遍历错误码描述表，
 *          找到匹配的错误码后返回对应的中文描述。如果找不到匹配的错误码，
 *          则返回"未知错误码"。
 * 
 * @param error_code 错误码值
 * @return 错误描述字符串，如果找不到则返回"未知错误码"
 * 
 * @note 返回的字符串是静态常量，不需要释放内存
 * @warning 如果传入无效的错误码，会返回"未知错误码"
 * 
 * @see protocol_error_t
 */
const char* protocol_get_error_string(protocol_error_t error_code) {
    LOG_DEBUG(LOG_MODULE_NAME, "获取错误码描述: error_code=%d", error_code);
    
    // 计算错误码描述表的大小
    const size_t count = sizeof(error_descriptions) / sizeof(error_description_t);
    LOG_DEBUG(LOG_MODULE_NAME, "错误码描述表大小: %zu", count);
    
    // 遍历错误码描述表，查找匹配的错误码
    for (size_t i = 0; i < count; i++) {
        if (error_descriptions[i].code == error_code) {
            // 找到匹配的错误码，返回对应的描述
            LOG_DEBUG(LOG_MODULE_NAME, "找到错误码 %d: 描述='%s'", 
                      error_code, error_descriptions[i].description);
            LOG_INFO(LOG_MODULE_NAME, "错误码 %d 描述: %s", error_code, error_descriptions[i].description);
            return error_descriptions[i].description;
        }
    }
    
    // 未找到匹配的错误码，返回默认描述
    LOG_WARN(LOG_MODULE_NAME, "未找到错误码 %d，返回默认描述", error_code);
    LOG_INFO(LOG_MODULE_NAME, "错误码 %d 描述: 未知错误码", error_code);
    return "未知错误码";
}

/**
 * @brief 检查错误码是否为成功
 * @details 判断给定的错误码是否表示操作成功。只有PROTOCOL_SUCCESS
 *          被认为是成功状态，其他所有错误码都被认为是失败状态。
 * 
 * @param error_code 错误码值
 * @return 成功返回true(1)，失败返回false(0)
 * 
 * @note 这是一个简单的比较函数，性能开销很小
 * @see PROTOCOL_SUCCESS
 */
int protocol_is_success(protocol_error_t error_code) {
    LOG_DEBUG(LOG_MODULE_NAME, "检查错误码是否为成功: error_code=%d", error_code);
    
    // 检查错误码是否等于成功码
    int is_success = (error_code == PROTOCOL_SUCCESS);
    LOG_DEBUG(LOG_MODULE_NAME, "错误码 %d 成功性检查: %s", error_code, is_success ? "成功" : "失败");
    LOG_INFO(LOG_MODULE_NAME, "错误码 %d 成功性检查结果: %d", error_code, is_success);
    
    return is_success;
}

/**
 * @brief 检查错误码是否为致命错误
 * @details 判断给定的错误码是否为致命错误。致命错误通常会导致程序无法继续
 *          正常运行，需要立即处理或终止程序。函数在错误码描述表中查找对应的
 *          致命性标志。如果找不到匹配的错误码，默认认为是致命错误。
 * 
 * @param error_code 错误码值
 * @return 致命错误返回true(1)，非致命错误返回false(0)
 * 
 * @note 未知错误码默认被认为是致命错误，以确保安全
 * @warning 致命错误需要立即处理，不能忽略
 * 
 * @see protocol_error_t
 */
int protocol_is_fatal_error(protocol_error_t error_code) {
    LOG_DEBUG(LOG_MODULE_NAME, "检查错误码是否为致命错误: error_code=%d", error_code);
    
    // 计算错误码描述表的大小
    const size_t count = sizeof(error_descriptions) / sizeof(error_description_t);
    LOG_DEBUG(LOG_MODULE_NAME, "错误码描述表大小: %zu", count);
    
    // 遍历错误码描述表，查找匹配的错误码
    for (size_t i = 0; i < count; i++) {
        if (error_descriptions[i].code == error_code) {
            // 找到匹配的错误码，获取致命性标志
            int is_fatal = error_descriptions[i].is_fatal;
            LOG_DEBUG(LOG_MODULE_NAME, "找到错误码 %d: 致命性=%d, 描述='%s'", 
                      error_code, is_fatal, error_descriptions[i].description);
            LOG_INFO(LOG_MODULE_NAME, "错误码 %d 致命性检查结果: %d", error_code, is_fatal);
            return is_fatal;
        }
    }
    
    // 未找到匹配的错误码，默认认为是致命错误（安全策略）
    LOG_WARN(LOG_MODULE_NAME, "未找到错误码 %d，默认认为是致命错误", error_code);
    LOG_INFO(LOG_MODULE_NAME, "错误码 %d 致命性检查结果: 1 (默认)", error_code);
    return 1; /* 未知错误默认为致命错误 */
}

/**
 * @brief 检查错误码是否为可恢复错误
 * @details 判断给定的错误码是否为可恢复错误。可恢复错误是指可以通过重试、
 *          重新初始化或其他恢复措施来解决的错误。函数在错误码描述表中查找
 *          对应的可恢复性标志。如果找不到匹配的错误码，默认认为是不可恢复错误。
 * 
 * @param error_code 错误码值
 * @return 可恢复错误返回true(1)，不可恢复错误返回false(0)
 * 
 * @note 未知错误码默认被认为是不可恢复错误，以确保安全
 * @warning 不可恢复错误通常需要人工干预或程序重启
 * 
 * @see protocol_error_t
 */
int protocol_is_recoverable_error(protocol_error_t error_code) {
    LOG_DEBUG(LOG_MODULE_NAME, "检查错误码是否为可恢复错误: error_code=%d", error_code);
    
    // 计算错误码描述表的大小
    const size_t count = sizeof(error_descriptions) / sizeof(error_description_t);
    LOG_DEBUG(LOG_MODULE_NAME, "错误码描述表大小: %zu", count);
    
    // 遍历错误码描述表，查找匹配的错误码
    for (size_t i = 0; i < count; i++) {
        if (error_descriptions[i].code == error_code) {
            // 找到匹配的错误码，获取可恢复性标志
            int is_recoverable = error_descriptions[i].is_recoverable;
            LOG_DEBUG(LOG_MODULE_NAME, "找到错误码 %d: 可恢复性=%d, 描述='%s'", 
                      error_code, is_recoverable, error_descriptions[i].description);
            LOG_INFO(LOG_MODULE_NAME, "错误码 %d 可恢复性检查结果: %d", error_code, is_recoverable);
            return is_recoverable;
        }
    }
    
    // 未找到匹配的错误码，默认认为是不可恢复错误（安全策略）
    LOG_WARN(LOG_MODULE_NAME, "未找到错误码 %d，默认认为是不可恢复错误", error_code);
    LOG_INFO(LOG_MODULE_NAME, "错误码 %d 可恢复性检查结果: 0 (默认)", error_code);
    return 0; /* 未知错误默认为不可恢复 */
}

/* ==================== 错误码转换函数实现 ==================== */

/**
 * @brief 将buffer_error_t转换为protocol_error_t
 * @details 将缓冲区错误码转换为对应的协议错误码。这个函数用于消除
 *          枚举类型隐式转换警告，提供显式的错误码转换。
 * 
 * @param buffer_error 缓冲区错误码值
 * @return 对应的协议错误码
 * 
 * @note buffer_error_t的枚举值与protocol_error_t有对应关系：
 *       - BUFFER_SUCCESS (0) -> PROTOCOL_SUCCESS (0)
 *       - BUFFER_ERROR_NULL_POINTER (1) -> PROTOCOL_ERROR_NULL_POINTER (2)
 *       - BUFFER_ERROR_INVALID_PARAM (2) -> PROTOCOL_ERROR_INVALID_PARAM (1)
 *       - BUFFER_ERROR_OUT_OF_BOUNDS (3) -> PROTOCOL_ERROR_BUFFER_OVERFLOW (4)
 *       - BUFFER_ERROR_INSUFFICIENT_DATA (4) -> PROTOCOL_ERROR_BUFFER_TOO_SMALL (3)
 * 
 * @warning 未知的buffer_error值会返回PROTOCOL_ERROR_UNKNOWN
 * 
 * @see buffer_error_t
 * @see protocol_error_t
 */
protocol_error_t buffer_error_to_protocol_error(int buffer_error) {
    LOG_DEBUG(LOG_MODULE_NAME, "转换缓冲区错误码到协议错误码: buffer_error=%d", buffer_error);
    
    switch (buffer_error) {
        case 0: /* BUFFER_SUCCESS */
            LOG_DEBUG(LOG_MODULE_NAME, "缓冲区错误码转换: SUCCESS -> PROTOCOL_SUCCESS");
            return PROTOCOL_SUCCESS;
        
        case 1: /* BUFFER_ERROR_NULL_POINTER */
            LOG_DEBUG(LOG_MODULE_NAME, "缓冲区错误码转换: NULL_POINTER -> PROTOCOL_ERROR_NULL_POINTER");
            return PROTOCOL_ERROR_NULL_POINTER;
        
        case 2: /* BUFFER_ERROR_INVALID_PARAM */
            LOG_DEBUG(LOG_MODULE_NAME, "缓冲区错误码转换: INVALID_PARAM -> PROTOCOL_ERROR_INVALID_PARAM");
            return PROTOCOL_ERROR_INVALID_PARAM;
        
        case 3: /* BUFFER_ERROR_OUT_OF_BOUNDS */
            LOG_DEBUG(LOG_MODULE_NAME, "缓冲区错误码转换: OUT_OF_BOUNDS -> PROTOCOL_ERROR_BUFFER_OVERFLOW");
            return PROTOCOL_ERROR_BUFFER_OVERFLOW;
        
        case 4: /* BUFFER_ERROR_INSUFFICIENT_DATA */
            LOG_DEBUG(LOG_MODULE_NAME, "缓冲区错误码转换: INSUFFICIENT_DATA -> PROTOCOL_ERROR_BUFFER_TOO_SMALL");
            return PROTOCOL_ERROR_BUFFER_TOO_SMALL;
        
        default:
            LOG_WARN(LOG_MODULE_NAME, "未知的缓冲区错误码: %d，返回PROTOCOL_ERROR_UNKNOWN", buffer_error);
            return PROTOCOL_ERROR_UNKNOWN;
    }
}
